package be.kuleuven.cs.mop.gui.dialogs;


import java.awt.Dimension;
import java.awt.Frame;
import java.awt.GridBagConstraints;
import java.awt.event.ActionEvent;
import java.util.HashMap;
import java.util.HashSet;
import java.util.logging.Level;

import javax.swing.JCheckBox;

import be.kuleuven.cs.mop.app.controllers.Controllers;
import be.kuleuven.cs.mop.domain.exceptions.InvalidCurrentUserException;
import be.kuleuven.cs.mop.domain.model.Project;
import be.kuleuven.cs.mop.domain.model.Task;
import be.kuleuven.cs.mop.domain.model.TaskType;
import be.kuleuven.cs.mop.domain.model.impl.Field;
import be.kuleuven.cs.mop.gui.components.ActionButton;
import be.kuleuven.cs.mop.gui.components.ComboSelector;
import be.kuleuven.cs.mop.gui.components.ScheduleInput;
import be.kuleuven.cs.mop.gui.components.SelectionList;
import be.kuleuven.cs.mop.gui.components.TaskFieldsInput;
import be.kuleuven.cs.mop.gui.components.Wrapper;
import be.kuleuven.cs.mop.gui.util.SwingUtils;



/**
 * {@link ActionDialog} for the "Create Task" use case
 */
public class CreateTaskDialog extends DynamicActionDialog<TaskType> {
	private static final long serialVersionUID = 1L;
	
	private JCheckBox				assign			= new JCheckBox();
	private SelectionList<Task>		dependencies;
	private Fields					fields			= new Fields();
	private ComboSelector<Project>	project;
	private ScheduleInput			schedule		= new ScheduleInput();
	private ComboSelector<TaskType>	type;
	
	
	public CreateTaskDialog(final Frame parent, final Controllers controllers) {
		super(parent, "Create Task", controllers);
		final GridBagConstraints gbc = SwingUtils.getGBC();
		
		try {
			dependencies	= new SelectionList<Task>(
					getControllers().getControllerTasks().getUserTasks(), true);
			
			project			= new ComboSelector<Project>(
					getControllers().getControllerProjects().getProjects().toArray(
							new Project[0]));
			
			type			= new ComboSelector<TaskType>(
					getControllers().getControllerTasks().getTaskTypes().toArray(
							new TaskType[0]));
		} catch (final Exception e) {
			log(e);
			dispose();
			return;
		}
		
		type.addActionListener(new UpdateListener());
		gbc.gridx	= 0;
		gbc.gridy	= 0;
		gbc.gridwidth	= 2;
		add(type, gbc);
		
		gbc.gridy	= 1;
		gbc.gridwidth	= 1;
		add(project, gbc);
		
		assign.setSelected(false);
		gbc.gridx	= 1;
		add(assign, gbc);
		
		gbc.gridx	= 0;
		gbc.gridy	= 2;
		gbc.gridwidth = 2;
		add(schedule, gbc);
		
		gbc.gridy	= 3;
		add(new ActionButton("Create", new Dimension(150, 32), this), gbc);
		
		fields.setTaskType(type.getSelection());
		gbc.gridx	= 2;
		gbc.gridy	= 0;
		gbc.gridheight	= 4;
		add(fields, gbc);
		
		gbc.gridx	= 3;
		add(this.dependencies.wrap(new Dimension(300, 250)), gbc);
		
		display();
	}
	
	
	
	@Override
	protected TaskType getSelection() {
		return type.getSelection();
	}
	
	@Override
	protected void handle(ActionEvent event) throws Exception {
		final Project project = this.project.getSelection();
		if (assign.isSelected() && (project == null)) {
			log("Please select a (valid) Project", Level.WARNING);
			return;
		}
		
		final Task task;
		try {
			task = getControllers().getControllerTasks().createTask(
					schedule.read(),
					new HashSet<Task>(dependencies.getSelection()),
					fields.read(),
					type.getSelection());
		} catch (final Exception e) {
			log(e);
			return;
		}
		
		try {
			if (assign.isSelected())
				getControllers().getControllerProjects().assignTaskToProject(
						task, project);
			log("Created Task (ID %d)", task.hashCode());
		} catch (final Exception e) {
			//	ignored
		}
		
		showUpdatedTasks();
	}
	
	private final void showUpdatedTasks() {
		dispose();
		
		try {
			new InfoDialog((Frame)getOwner(), new SelectionList<Task>(
					getControllers().getControllerTasks().getUserTasks(), false)
					.wrap(new Dimension(400, 400)));
		} catch (final InvalidCurrentUserException e) {
			log(e);
		}
	}
	
	@Override
	protected void update(final TaskType selection) {
		fields.setTaskType(selection);
	}
	
	
	
	
	
	
	
	
	
	
	private static class Fields extends Wrapper<TaskFieldsInput> {
		private static final long serialVersionUID = 1L;
		
		
		public Fields() {
			this(null);
		}
		private Fields(final TaskFieldsInput input) {
			super(input);
		}
		
		
		
		public HashMap<String, Field> read() {
			try {
				return new HashMap<String, Field>(get().read());
			} catch (final Exception e) {
				//	ignored
			}
			return null;
		}
		
		public void setTaskType(final TaskType type) {
			removeAll();
			if (type != null)
				set(new TaskFieldsInput(type));
		}
		
	}
	
}